package cn.edu.sjtu.adc.overprovision.instance;

import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Locale;

import org.apache.log4j.Logger;

import cn.edu.sjtu.adc.overprovision.logReader.CsvReader;


public class InfoGenerator {
	final String TIME_PATTERN = "yyyy-MM-dd hh:mm:ss";
//	final long FINISH_SYMBOL = -1;
	final String TIME = "time";
	final String INSTANCE = "instance";
	Logger logger = Logger.getLogger(InfoGenerator.class);

	/**
	 * Read the time and the related instance information in the log file.
	 * 
	 * @return The HashMap<Long, String> with time as key and instance as value 
	 * @param The file path
	 * @author Lola
	 */
	public LinkedHashMap<Long, Integer> interpretLog(String filePath) {
		LinkedHashMap<Long, Integer> instanceInfo = new LinkedHashMap<Long, Integer>();  
		SimpleDateFormat simpledateformat = new SimpleDateFormat(TIME_PATTERN, Locale.SIMPLIFIED_CHINESE);
		
		try {
			CsvReader csvReader = new CsvReader(filePath);
			
			long startTime = 0;
			if(csvReader.readRecord()){
				startTime = simpledateformat.parse(csvReader.get(TIME)).getTime();
				int instance = Integer.parseInt(csvReader.get(INSTANCE));
				instanceInfo.put((long) 0, instance);
			}
			while(csvReader.readRecord()){
				long time = simpledateformat.parse(csvReader.get(TIME)).getTime() - startTime;
				int instance = Integer.parseInt(csvReader.get(INSTANCE));
				instanceInfo.put(time, instance);
			}
			
		} catch (Exception e) {
			logger.error(e);
		}
		return instanceInfo;
	}
	
	/**
	 * Calculate the value of the actual exceeded the standard by multiply the time and exceeded instance number 
	 * 
	 * @return The HashMap<Long, String> with time as key and instance as value 
	 * @param the standard configuration of time and instance number
	 * @param the actual configuration of time and instance number 
	 * @author Lola
	 */
	public long compareValue(LinkedHashMap<Long, Integer> standard, LinkedHashMap<Long, Integer> actual){
		long overProision = 0;
		Iterator<Long> standardIterator = standard.keySet().iterator();
		Iterator<Long> actualIterator = actual.keySet().iterator();
		long preTime = 0;
		long currentTime = 0;
		long preActualTime = 0;
		long preStandardTime = 0;
		long standardTime = 0;
		long actualTime = 0;
		boolean currentIsActual = true;
		
		/*
		 * The first two key values of will all be 0 as the function interpretLog
		 * ensured
		 */
		if(standardIterator.hasNext() || actualIterator.hasNext()){
			preStandardTime = standardIterator.next();
			preActualTime = actualIterator.next();
			preTime = preStandardTime>preActualTime? preActualTime : preStandardTime;
		}
		if(standardIterator.hasNext() || actualIterator.hasNext()){
			standardTime = standardIterator.next();
			actualTime = actualIterator.next();
			currentIsActual = actualTime > standardTime ? false : true;
			currentTime = currentIsActual? actualTime:standardTime;
			int standardInstance = standard.get(preStandardTime).intValue();
			int actualInstance = actual.get(preActualTime).intValue();
			if(actualInstance > standardInstance){
				overProision += (actualInstance - standardInstance) * (currentTime - preTime);
			}
			preTime = actualTime;		
		}
		
		while(standardIterator.hasNext() && actualIterator.hasNext()){
			if (currentIsActual) {
				preActualTime = actualTime;
				actualTime = actualIterator.next();
			} else {
				preStandardTime = standardTime;
				standardTime = standardIterator.next();
			}
			currentIsActual = actualTime > standardTime ? false : true;
			currentTime = currentIsActual ? standardTime : actualTime;
			int standardInstance = standard.get(preStandardTime).intValue();
			int actualInstance = actual.get(preActualTime).intValue();

			if (actualInstance > standardInstance) {
				overProision += (actualInstance - standardInstance) * (currentTime - preTime);
			}
			preTime = currentTime;
		}
		
		/*
		 * The situation that it takes more time than the standard solution to finish the work.
		 * */
		while(actualIterator.hasNext()){
			preActualTime = actualTime;
			actualTime = actualIterator.next();
			overProision += actual.get(preActualTime).intValue() * (actualTime - preActualTime);			
		}
		
		/*
		 * The situation that it takes less time than the standard solution to finish the work.
		 * */
		while(actualIterator.hasNext()){
			preStandardTime = standardTime;
			standardTime = standardIterator.next();
			overProision -= actual.get(preStandardTime).intValue() * (standardTime - preStandardTime);			
		}
		return overProision;
	}
}
